package com.higgins.eventtracking.server;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.jdo.Query;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.higgins.eventtracking.client.SecurityAccessDeniedException;
import com.higgins.eventtracking.client.dto.AssetDTO;
import com.higgins.eventtracking.client.dto.FinanceGoalDTO;
import com.higgins.eventtracking.server.dataModel.Asset;
import com.higgins.eventtracking.server.dataModel.FinanceGoal;


public class AssetTrackingDataService extends GenericDataStoreService	{
	public void addAsset(String amount, String account) throws SecurityAccessDeniedException	{
//		this.checkAuthority();
		addAsset(Double.parseDouble(amount), account);
	}
	public void addAsset(String amount, String account, String accountRepayment, String monthlyRepayment, String monthlyInterest) throws SecurityAccessDeniedException	{
		this.checkAuthority();
		addAsset(Double.parseDouble(amount), account, accountRepayment, Double.parseDouble(monthlyRepayment), Double.parseDouble(monthlyInterest));
	}
	@SuppressWarnings("unchecked")
	public Double retrieveAssetAmount(String account) throws SecurityAccessDeniedException	{
		this.checkAuthority();
		Query query=pm.newQuery(Asset.class);
		if (account!=null)	{
			query.setFilter("account==accountParam");
			query.declareParameters("String accountParam");
			List<Asset> results = (List<Asset>)query.execute(account);
			return sumOfAssetAmounts(results);
		} else	{
			List<Asset> results = (List<Asset>)query.execute();
			return sumOfAssetAmounts(results);
		}
	}
	public Double retrieveAssetAmount(String account, Date end) throws SecurityAccessDeniedException	{
		this.checkAuthority();
		Query query=pm.newQuery(Asset.class);
		if (account!=null)	{
			query.setFilter("account==accountParam && timestamp < dateParam");
			query.declareParameters("String accountParam, java.util.Date dateParam");
			List<Asset> results = (List<Asset>)query.execute(account, end);
			return sumOfAssetAmounts(results);
		} else	{
			query.setFilter("timestamp < dateParam");
			query.declareParameters("java.util.Date dateParam");
			List<Asset> results = (List<Asset>)query.execute(end);
			return sumOfAssetAmounts(results);
		}
	}	
	public void addAsset(Double amount, String account)	{
		Asset asset = new Asset(amount, account);
		insertAsset(asset);
	}
	private void addAsset(Double amount, String account, String accountRepayment, Double monthlyRepayment, Double monthlyInterest)	{
		Asset asset = new Asset(amount, account, accountRepayment, monthlyRepayment, monthlyInterest);
		insertAsset(asset);
	}
	public void insertAsset(Asset asset)	{
		pm.makePersistent(asset);
	}
	public void updateAsset(Asset asset)	{
		pm.makePersistent(asset);
	}
	public String updateAsset(AssetDTO dto)	{
		Asset asset = null;
		if (dto.getId()!=null)	{
			asset = (Asset)pm.getObjectById(Asset.class, dto.getId());
		} else {
			asset = new Asset();
		}
		asset.update(dto);
		pm.makePersistent(asset);
		return asset.getId().toString();
	}
	private Double sumOfAssetAmounts(List<Asset> results) throws SecurityAccessDeniedException	{
		this.checkAuthority();
		Double total = 0.0;
		for (Asset asset:results)
			total+=asset.getAmount();
		return total;
	}
	public List<Asset> retrieveLoans() throws SecurityAccessDeniedException	{
//		this.checkAuthority();
		Query query=pm.newQuery(Asset.class);
		query.setFilter("accountType==accountTypeParam");
		query.declareParameters("String accountTypeParam");
		query.setOrdering("timestamp desc");
		List<Asset> results = (List<Asset>)query.execute("Loan");
		return results;
	}
	
	public List<AssetDTO> retrieveAssets() throws SecurityAccessDeniedException	{
		this.checkAuthority();
		Query query=pm.newQuery(Asset.class);
//		query.setOrdering("timestamp desc");
		List<Asset> assets = (List<Asset>)query.execute();
		List<AssetDTO> assetDTOs = new ArrayList<AssetDTO>();
		for (Asset asset:assets)	{
			AssetDTO assetDTO = asset.toDTO();
			assetDTOs.add(assetDTO);
		}
		return assetDTOs;
	}
	
	public List<FinanceGoalDTO> retrieveGoals() throws SecurityAccessDeniedException	{
		this.checkAuthority();
		
		Query query=pm.newQuery(FinanceGoal.class);
		query.setOrdering("priority asc");
		List<FinanceGoal> goals = (List<FinanceGoal>)query.execute();
		List<FinanceGoalDTO> goalDTOs = new ArrayList<FinanceGoalDTO>();
		for (FinanceGoal goal:goals)	{
			FinanceGoalDTO goalDTO = goal.toDTO();
			goalDTOs.add(goalDTO);
		}
		return goalDTOs;
	}
	public Boolean insertGoal(String goal, Double price, Integer priority)	throws SecurityAccessDeniedException	{
		this.checkAuthority();
		FinanceGoal goalObject = new FinanceGoal();
		goalObject.setGoal(goal);
		goalObject.setPrice(price);
		goalObject.setPriority(priority);
		pm.makePersistent(goalObject);
		return true;
	}
	
	public Double retrieveForecastedTotalAssets(Boolean employed, Date now, Date forecastDate)	throws IllegalArgumentException	{
			Double totalAssets;
			try {
				totalAssets = retrieveAssetAmount(null);
				
				Double profitToEndOfNextQuarter = calculateForecastProfit(employed, now, forecastDate);
				
				Double forecast = totalAssets + profitToEndOfNextQuarter;
				return forecast;
			} catch (SecurityAccessDeniedException e) {
				return null;
			}
	}
	public Double calculateForecastProfit(boolean employed, Date now, Date forecastDate)	{
		IncomeSettingsDataService incomeService = new IncomeSettingsDataService();
		FinanceTrackingDataService financeService = new FinanceTrackingDataService();
		try	{
			incomeService.openPersistenceManager();
			financeService.openPersistenceManager();
			return calculateForecastProfit(employed, now, forecastDate, incomeService, financeService);

		} catch (Exception e)	{
			return null;
		} finally {
			incomeService.closePersistenceManager();
			financeService.closePersistenceManager();
		}
	}
	public Double calculateForecastProfit(boolean employed, Date now, Date forecastDate, IncomeSettingsDataService incomeService, FinanceTrackingDataService financeService) throws SecurityAccessDeniedException	{
		Double income = Double.parseDouble(incomeService.retrieveIncome());
		Double fixedOutgoing = Double.parseDouble(incomeService.retrieveOutgoing());
		Double severableOutgoing = Double.parseDouble(incomeService.retrieveSeverableOutgoing());
		
		Double monthlyProfitBeforeExpenses = (employed?income:0.0) - fixedOutgoing - (employed?severableOutgoing:0.0);
		Double averageWeeklySpend = financeService.retrieveAverageWeeklySpend(now, false);
		Double yearlyExpenses = financeService.retrieveYearlyExpensesThisMonth(now);

		Integer weeksToEONQ = DateUtility.getWeeksTo(now, forecastDate);
		Integer monthsToEONQ = DateUtility.getMonthsTo(now, forecastDate);
		Integer weekThisMonth = DateUtility.getWeekNumberOfMonth(now);
		
		Double totalProfitBeforeExpenses = monthlyProfitBeforeExpenses * (monthsToEONQ);
		Double totalExpenses = averageWeeklySpend * ((weekThisMonth-1) + weeksToEONQ);
		
		return (totalProfitBeforeExpenses - totalExpenses - yearlyExpenses);
	}	
	public String deleteAsset(Long id) throws IllegalArgumentException	{
		Asset asset = null;
		if (id!=null)	{
			asset = (Asset)pm.getObjectById(Asset.class, id);
			pm.deletePersistent(asset);
		} 
		return asset.getId().toString();
	}
}
